Skip to content

Conversation

@marc-antoine-girard
Copy link
Contributor

@marc-antoine-girard marc-antoine-girard commented Jul 9, 2022

Description

As described by the issue, when a new instance of SerializableInterface is added in an array using the inspector's gizmo, Unity clones the last SerializableInterface. Since rawReference is [SerializeReference], the reference of the object is copied by ref, which makes the new element references the same instance as the previous one.

Editing the last element will modify the previous one too.

This bug should only applies to pure serializable C# classes stored in the rawReference's field. This is why I moved the fix from SerializableInterfacePropertyDrawer to RawReferenceDrawer in my previous commits.

This fixes #19 without adding any dependencies and in an easy-to read (ish) fashion.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code follows the style guidelines of this project (added first constants, had to guess the naming convention)
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings

Unrelated Note: Unless I'm missing something, the ReferenceDrawer instantiated in GetReferenceDrawer(..) could be reused for every instances, the same way Unity reuses the PropertyDrawer for multiple instances to avoid GC.

Since it only applies to SerializableInterfaces in Raw mode, it made more sense to only do it in RawReferenceDrawer instead of SerializableInterfacePropertyDrawer. Tested the same way, no apparent diff.
Would only work in UNITY_2021_1_OR_NEWER otherwise
Copy link
Owner

@Thundernerd Thundernerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! I've added some questions and some formatting change requests, but can't blame you for that since I haven't specified the formatting anywhere :)

activeDrawer = null;
serializedProperty = property;
genericType = GetGenericArgument();

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the reason for this added blank line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems my Rider thought it looked better :) I'll remove it!

Comment on lines +14 to +15
private static object previousReferenceValue;
private static string previousPropertyPath;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the reason for making this static?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It used to be a local variable in SerializableInterfacePropertyDrawer.cs. The goal was to store the last element and check if the new element's rawReference object points to the same instance as the previous one. If it does AND this isn't actually the same variable (we know that using the propertyPath, see line 115 in RawReferenceDrawer.cs), then we need to create a new instance and reassign the values (line 124 - 125 in RawReferenceDrawer.cs). I've moved the code to RawReferenceDrawer.cs since it made more sense because it only applies to rawReferences, but since we always create a new instance for that drawer, we either need to pass the values of the previous object to its constructor, or save it in a static variable.

Passing it using the constructor would also add unnecessary code in SerializableInterfacePropertyDrawer.cs. So the static way made sense in that regard. I hope it clears up things a bit. Also, it wouldn't need to be static if the instance of ReferenceDrawers where reused :)

@Thundernerd
Copy link
Owner

Unrelated Note: Unless I'm missing something, the ReferenceDrawer instantiated in GetReferenceDrawer(..) could be reused for every instances, the same way Unity reuses the PropertyDrawer for multiple instances to avoid GC.

Ah I hadn't thought about that. Might be interesting to take a look at! I'll add that to the list

@marc-antoine-girard
Copy link
Contributor Author

I'm doing the changes and update the PR, thanks for your comments. This also is my first contribution on Github, so I'm still learning! :)

@marc-antoine-girard
Copy link
Contributor Author

marc-antoine-girard commented Jul 11, 2022

@Thundernerd Also, in RawReferenceDrawer.cs, you have this property, RawReferenceValue from which I added a setter.
From what I understand, managedReferenceValue didn't exist in earlier version of Unity? If that's the case, in ReferenceDrawer.cs, managedReferenceValue is used everywhere. It might be worth moving the property to its base class. :)

Edit: Implemented in #27

@Thundernerd Thundernerd merged commit 9d2bfb8 into Thundernerd:main Jul 22, 2022
@Thundernerd
Copy link
Owner

🎉 This PR is included in version 1.7.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Collection editing

2 participants